"""
此版本需要手动更改PDDAccessToken变量以跳过验证
"""

import json
import os
import requests
from bs4 import BeautifulSoup
from tqdm import tqdm
import asyncio
import aiofiles  # 异步操作文件


def parse_json_with_error_handling(json_str):
    try:
        # 尝试解析 JSON 字符串
        parsed_json = json.loads(json_str)
        return parsed_json
    except json.JSONDecodeError as e:
        # 获取错误信息
        error_message = str(e)
        print(f"JSON 解析错误(不用管): {error_message}")
        # 找到错误位置
        error_pos = e.pos
        # 尝试截断字符串并重新解析
        truncated_json = json_str[:error_pos]
        try:
            parsed_json = json.loads(truncated_json)
            return parsed_json
        except json.JSONDecodeError:
            print("即使截断后也无法解析 JSON 字符串")
            return None


# 异步函数
async def downVideoByUrl(url):
    # 添加 cookies
    cookies = {
        # 成功跳过验证   但是肯定有时间  还得重新登录   收到个短信?
        'PDDAccessToken': 'H2ABJ6UB6QVIPXA4O6FO4RDZPGL5Y54WGNKBCGDPAUNSRVVJJEQA12022a1',
        # 更多 cookies...
    }

    # 发送带有 cookies 的请求并获取响应
    response = requests.get(url, cookies=cookies)

    # 需要下来的视频流地址
    needDown = ''
    # 直播间名称
    homeName = ''
    # 买的东西
    showName = ''

    # 检查请求是否成功
    if response.status_code == 200:
        # 解析HTML
        soup = BeautifulSoup(response.text, 'html.parser')

        # 查找所有的 <script> 标签
        script_tags = soup.find_all('script')

        # 输出每个 <script> 标签的内容
        for script in script_tags:
            # 输出 <script> 标签的文本内容
            script_content = script.string
            if script_content is None:
                # 如果没有直接的 string 属性，尝试获取所有文本
                script_content = script.get_text()
            if "window.rawData" in script_content:
                objStr = script_content.replace(' window.rawData=', '')
                objStr = objStr.strip()
                # print(objStr)
                if "null;" == objStr:
                    print("尚未登录,请重新登录!")
                    raise ValueError("尚未登录,请重新登录! 或者检查是否开播!")
                else:
                    # 去转义
                    objJson = parse_json_with_error_handling(objStr)
                    # 直播间名称
                    homeName = objJson['store']['shareInfo']['pinxiaoquanShareTitle']
                    # 所有视频地址
                    playUrlList = objJson['store']['playUrlList']
                    for index, item in enumerate(playUrlList):
                        if index == 0:
                            # 获取第一个视频地址
                            playUrl = item['playUrl']
                            # 下载第一个
                            needDown = playUrl

    else:
        print("请求失败，状态码:", response.status_code)

    print(homeName + 'start...')
    # 设置输出文件地址
    folder_path = homeName
    # 检查文件夹是否存在
    if not os.path.exists(folder_path):
        # 如果不存在，则创建文件夹
        os.makedirs(folder_path)
        print(f"文件夹 '{folder_path}' 创建成功。")
    else:
        print(f"文件夹 '{folder_path}' 已存在。")
    output_filename = folder_path + '/' + homeName + '.mp4'

    # 发送请求并获取响应
    response = requests.get(needDown, stream=True)

    # 获取文件大小
    total_size_in_bytes = int(response.headers.get('content-length', 0))

    # 检查请求是否成功
    if response.status_code == 200:
        # 使用tqdm创建一个进度条
        progress_bar = tqdm(desc='正在获取' + homeName + '的内容',
                            total=total_size_in_bytes,
                            unit='iB',
                            unit_scale=True,
                            mininterval=1)

        # 以二进制模式打开文件，并写入数据
        async with aiofiles.open(output_filename, 'wb') as f:
            for data in response.iter_content(chunk_size=1024):
                size = await f.write(data)  # 异步等待
                progress_bar.update(size)

        # 关闭进度条
        progress_bar.close()

        print(f"视频已成功下载为 {output_filename}")
    else:
        print("下载失败，状态码:", response.status_code)


async def main():
    # 打开文件并读取每一行
    with open('../V1.2/pddAdr.txt', 'r', encoding='utf-8') as file:
        urls = file.readlines()
    await asyncio.gather(*[downVideoByUrl(url) for url in urls])


# 运行异步程序
asyncio.run(main())
